package com.itheima.prize.msg;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.prize.commons.config.RedisKeys;
import com.itheima.prize.commons.db.entity.*;
import com.itheima.prize.commons.db.service.*;
import com.itheima.prize.commons.utils.RedisUtil;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 活动信息预热，每隔1分钟执行一次
 * 查找未来1分钟内（含），要开始的活动
 */
@Component
public class GameTask {
    private final static Logger log = LoggerFactory.getLogger(GameTask.class);
    @Autowired
    private CardGameService gameService;
    @Autowired
    private CardGameProductService gameProductService;
    @Autowired
    private CardGameRulesService gameRulesService;
    @Autowired
    private GameLoadService gameLoadService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ViewGameProductnumService gameProductnumService;
    @Autowired
    private CardProductService cardProductService;

    @Scheduled(cron = "0 * * * * ?")
    public void execute() {
        //缓存开始时间
        long start = System.currentTimeMillis();
        //检查一分钟之内是否有抽奖活动开始
        List<CardGame> games = gameService.queryStartActivity();

        //没有，则结束定时任务
        if (games == null) {
            return;
        }

        //遍历把每个活动策略缓存到redis
        for (CardGame game : games) {
            Integer gameId = game.getId();
            //数据缓存预热成功，状态改为已加载
            game.setStatus(1);
            //修改数据库活动状态为已加载
            gameService.lambdaUpdate()
                    .eq(CardGame::getId,gameId)
                    .update(game);
            //将已加载的活动基本信息存入redis覆盖之前未加载的活动信息
            redisUtil.set(RedisKeys.INFO + gameId, game);

            //把活动开始时间和结束时间存入redis方便后续lua脚本调用
            redisUtil.set(RedisKeys.INFO + gameId + "_startTime", game.getStarttime().getTime());
            redisUtil.set(RedisKeys.INFO + gameId + "_endTime", game.getEndtime().getTime());

            //查询该活动奖品数量
            ViewGameProductnum gameProductnum = gameProductnumService.lambdaQuery()
                    .eq(ViewGameProductnum::getGameid, gameId)
                    .one();
            Long productNum = gameProductnum.getNum();


            //生成对应数量的随机时间戳当作令牌,作为中奖依据
            List<Long> tokenList = new ArrayList<>();
            long startTime = game.getStarttime().getTime();
            long endTime = game.getEndtime().getTime();
            long duration = endTime - startTime;
            for (int i = 0; i < productNum; i++) {
                long timeStamp = startTime + new Random().nextInt((int) duration);

                //防止短时间奖品过多,令牌重复
                long token = timeStamp * 1000 + new Random().nextInt(999);
                //添加到令牌集合中
                tokenList.add(token);
            }
            //对时间戳集合进行从小到大排序，存入redis
            Collections.sort(tokenList);
            redisUtil.rightPushAll(RedisKeys.TOKEN + gameId, tokenList);

            //查询该活动各个奖品的信息
            List<CardProductDto> cardProductDtos = gameLoadService.getByGameId(gameId);

            //定义list集合，存储奖品出现顺序
            ArrayList<Integer> productOrder = new ArrayList<>();
            //定义map集合，存储该活动对应的奖品信息
            HashMap<Integer, CardProductDto> productMap = new HashMap<>();

            Integer productId, amount;
            for (CardProductDto cardProductDto : cardProductDtos) {
                //获取当前奖品id
                productId = cardProductDto.getId();
                //将奖品id对应的奖品信息存入map集合
                productMap.put(productId,cardProductDto);
                //获取当前奖品数量
                amount = cardProductDto.getAmount();
                //将该奖品的id存入奖品顺序productOrder的list集合(存入次数为奖品次数)
                ArrayList<Integer> list = new ArrayList<>();
                for (int i = 0; i < amount; i++) {
                    list.add(i, productId);
                }
                productOrder.addAll(list);
            }

            //打乱奖品出现顺序productOrder的list集合
            Collections.shuffle(productOrder);

            //将每个时间戳和对应的奖品详情信息存入redis
            Map<String, Object> map = new LinkedHashMap<>();
            for (int i = 0; i < productOrder.size(); i++) {
                map.put(tokenList.get(i).toString(),productMap.get(productOrder.get(i)));
            }
            redisUtil.hmset(RedisKeys.TOKENS + gameId, map);

            //查询该活动对应的抽奖策略
            List<CardGameRules> ruleList = gameRulesService.lambdaQuery()
                    .eq(CardGameRules::getGameid, gameId)
                    .list();

            //将不同会员等级对应的最大抽奖次数和最大中奖次数分别存入存入redis

            HashMap<String, Object> maxEnterMap = new HashMap<>();
            HashMap<String, Object> maxGoalMap = new HashMap<>();
            for (CardGameRules cardGameRules : ruleList) {
                redisUtil.set(RedisKeys.MAXENTER + gameId + "_" + cardGameRules.getUserlevel(), cardGameRules.getEnterTimes());
                redisUtil.set(RedisKeys.MAXGOAL + gameId + "_" + cardGameRules.getUserlevel(), cardGameRules.getGoalTimes());
            }

            //缓存结束时间
            long end = System.currentTimeMillis();

            //打印日志缓存耗时
            log.info("缓存预热耗时:{}毫秒", end - start);
        }
    }
}
